﻿/****************************************************************************
 * Application   : Freekick Desktop Manager
 * Author        : sfreekick
 * Email         : sfreekick@gmail.com
 * Copyright     : (C) 2008 sfreekick
 * **************************************************************************/

/****************************************************************************
 *  This file is part of FreeKickManager.
 *
 *  FreeKickManager is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  FreeKickManager is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with FreeKickManager. If not, see <http://www.gnu.org/licenses/>.
 ****************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Xml;
using System.Threading;
using System.Text.RegularExpressions;
using HtmlAgilityPack;

namespace FreeKickManager
{
    public partial class FrmVisorPartidos : Form
    {
        private List<ReportePartido> reportes = null;
        private ReportePartido reportePropio = null;

        private int minuto = 1;
        private bool pausa = false;

        private string categoria = "";

        private int tiempoMinuto = 0;
        private int tiempoJugada = 0;

        private Partido partidoPropio = null;

        private bool actualizarClasificacion = false;
        private bool actualizarEventos = false;

        private List<Equipo> clasificacionProvisional = null;
        private List<Equipo> clasificacionInicial = null;
        private List<Equipo> equiposGrupo = null;


        public FrmVisorPartidos()
        {
            InitializeComponent();

            reportes = new List<ReportePartido>();
        }

        public FrmVisorPartidos(Partido part)
        {
            //Reporte estático

            InitializeComponent();

            this.categoria = "";
            this.partidoPropio = part;

            actualizarEventos = false;
            actualizarClasificacion = false;
        }

        public FrmVisorPartidos(string categoria)
        {
            //Reporte en directo - Ultima jornada

            InitializeComponent();

            reportes = new List<ReportePartido>();

            this.categoria = categoria; //senior ó youth
            this.partidoPropio = null;

            //Tiempos
            tiempoMinuto = Convert.ToInt32(FrmPrincipal.opciones.obtenerOpcion("tiempoMinuto"));
            tiempoJugada = Convert.ToInt32(FrmPrincipal.opciones.obtenerOpcion("tiempoJugada"));

            actualizarEventos = true;
            actualizarClasificacion = true;
        }

        private void cargaPartido()
        {
            CargadorXml.descargarXml("http://www.freekick.org/public/getdata.php?getdata=matchreport&datatype=xml&id=" + partidoPropio.id, "temp\\partido.xml");

            bwWorkerCarga.ReportProgress(1);

            reportePropio = CargadorXml.cargarReporte(partidoPropio, "temp\\partido.xml");

            bwWorkerCarga.ReportProgress(1);

            generarHtml(reportePropio);

            bwWorkerCarga.ReportProgress(1);

            //wbAlineacionInicial.Navigate(Application.StartupPath + "\\temp\\alineacion-inicial.html");
            //wbAlineacionFinal.Navigate(Application.StartupPath + "\\temp\\alineacion-final.html");

            bwWorkerCarga.ReportProgress(1);

            wbPartido.Navigate(Application.StartupPath + "\\temp\\reporte.html");

            bwWorkerCarga.ReportProgress(1);
        }

        private void cargarPartidosDirecto()
        {
            string xml = null;

            List<Partido> listaPartidos = new List<Partido>();

            if (FrmPrincipal.infoEquipo == null)
            {
                //Obtenemos los datos del grupo de liga de mi equipo
                xml = CargadorXml.descargarXml(@"http://www.freekick.org/public/getdata.php?getdata=ownclub&datatype=xml&username=" + FrmPrincipal.opciones.obtenerOpcion("usuario") + "&password=" + FrmPrincipal.opciones.obtenerOpcion("password"));

                if (xml != null)
                {
                    FrmPrincipal.infoEquipo = CargadorXml.cargarInformacionEquipo(xml);
                }
            }

            bwWorkerCarga.ReportProgress(1);

            //Obtenemos el último partido de mi equipo
            xml = CargadorXml.descargarXml("http://www.freekick.org/public/getdata.php?getdata=matches&type=league&squad=" + categoria + "&teamid=" + FrmPrincipal.infoEquipo.idEquipo + "&lastgames=1&played=true");

            if (xml != null)
            {
                List<Partido> misPartidos = CargadorXml.cargarListaPartidos(xml);

                listaPartidos.Add(misPartidos[0]);

                partidoPropio = misPartidos[0];
            }

            bwWorkerCarga.ReportProgress(1);

            if (FrmPrincipal.clasifSenior == null || FrmPrincipal.clasifJuvenil == null)
            {
                //Obtenemos la lista de equipos de mi grupo
                if (categoria.Equals("senior"))
                {
                    xml = CargadorXml.descargarXml(@"http://www.freekick.org/public/getdata.php?getdata=league&datatype=xml&league=" + FrmPrincipal.infoEquipo.liga + "&division=" + FrmPrincipal.infoEquipo.divisionSenior + "&series=" + FrmPrincipal.infoEquipo.serieSenior + "&squad=" + categoria + "&season=" + partidoPropio.temporada);
                }
                else
                {
                    xml = CargadorXml.descargarXml(@"http://www.freekick.org/public/getdata.php?getdata=league&datatype=xml&league=" + FrmPrincipal.infoEquipo.liga + "&division=" + FrmPrincipal.infoEquipo.divisionJuvenil + "&series=" + FrmPrincipal.infoEquipo.serieJuvenil + "&squad=" + categoria + "&season=" + partidoPropio.temporada);
                }

                if (xml != null)
                {
                    equiposGrupo = CargadorXml.cargarClasificacion(xml);
                }
            }
            else
            {
                if (categoria.Equals("senior"))
                {
                    equiposGrupo = clonarClasificacion(FrmPrincipal.clasifSenior);
                }
                else
                {
                    equiposGrupo = clonarClasificacion(FrmPrincipal.clasifJuvenil);
                }
            }
            
            bwWorkerCarga.ReportProgress(1);

            //Para cada equipo obtenemos su último partido
            foreach (Equipo eq in equiposGrupo)
            {
                //Si no es mi equipo...
                if (eq.id != FrmPrincipal.infoEquipo.idEquipo)
                {
                    xml = CargadorXml.descargarXml("http://www.freekick.org/public/getdata.php?getdata=matches&type=league&squad=" + categoria + "&teamid=" + eq.id + "&lastgames=1&played=true");

                    if (xml != null)
                    {
                        List<Partido> ultimosPartidos = CargadorXml.cargarListaPartidos(xml);

                        //Añadimos el partido si aún no estaba en la lista
                        if (listaPartidos.IndexOf(ultimosPartidos[0]) == -1)
                        {
                            listaPartidos.Add(ultimosPartidos[0]);
                        }
                    }
                }
            }

            bwWorkerCarga.ReportProgress(1);

            //Obtenemos los reportes de los partidos
            foreach (Partido part in listaPartidos)
            { 
                CargadorXml.descargarXml("http://www.freekick.org/public/getdata.php?getdata=matchreport&datatype=xml&id=" + part.id, "temp\\partido.xml");

                ReportePartido rep = CargadorXml.cargarReporte(part, "temp\\partido.xml");

                reportes.Add(rep);

                if (rep.partido.id.Equals(partidoPropio.id))
                {
                    reportePropio = rep;
                }
            }

            //Generamos los HTML de las alineaciones y el reporte
            generarHtml(reportePropio);

            //Cargar los HTML
            //wbAlineacionInicial.Navigate(Application.StartupPath + "\\temp\\alineacion-inicial.html");
            //wbAlineacionFinal.Navigate(Application.StartupPath + "\\temp\\alineacion-final.html");
            wbPartido.Navigate(Application.StartupPath + "\\temp\\reporte.html");

            bwWorkerCarga.ReportProgress(1);

            //Calculamos la clasificación previa a la jornada actual
            clasificacionInicial = calcularClasificacionInicial();
            clasificacionProvisional = clonarClasificacion(clasificacionInicial);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Play

            pausa = false;
            bwWorker.RunWorkerAsync();

            btnReproducir.Enabled = false;
            btnPausa.Enabled = true;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //Pausa

            pausa = true;

            btnReproducir.Enabled = true;
            btnPausa.Enabled = false;
        }

        private void bwWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //Primera parte
            for (int min = minuto; min <= 45; min++)
            {
                //Si se ha pulsado el botón de Pausa salimos del bucle
                if (pausa)
                    break;

                //Comenzamos el minuto actual
                bwWorker.ReportProgress(0, new EventoReporte(minuto, null, ""));

                //Buscamos las ocasiones de mi partido en el minuto actual
                List<Ocasion> ocasionesMinuto = reportePropio.buscarOcasiones(minuto);

                foreach (Ocasion oc in ocasionesMinuto)
                {
                    bwWorker.ReportProgress(1, new EventoReporte(minuto, null, "Minuto " + oc.minuto));

                    foreach (string jugada in oc.jugadas)
                    {
                        bwWorker.ReportProgress(1, new EventoReporte(minuto, null, jugada));

                        Thread.Sleep(tiempoJugada);
                    }

                    bwWorker.ReportProgress(1, new EventoReporte(minuto, null, ""));
                }


                //Buscamos las ocasiones del minuto de juego actual para cada partido del grupo
                if (actualizarEventos)
                {
                    foreach (ReportePartido rep in reportes)
                    {
                        ocasionesMinuto = rep.buscarOcasiones(min);

                        //Buscamos si hay goles en las ocasiones
                        foreach (Ocasion oc in ocasionesMinuto)
                        {
                            if (oc.existeEnJugadas("¡GOL!"))
                            {
                                //Reportamos el gol
                                EventoReporte ev = new EventoReporte(minuto, rep.partido, oc.jugadas[oc.jugadas.Count - 1]);
                                bwWorker.ReportProgress(0, ev);
                            }
                        }
                    }
                }

                //Incrementamos el minuto actual
                Thread.Sleep(tiempoMinuto);
                minuto++;
            }

            
            //Intermedio
            if(!pausa)
                bwWorker.ReportProgress(0, new EventoReporte(minuto, null, "DESCANSO PARTIDOS"));


            //Incrementamos el minuto actual
            Thread.Sleep(tiempoMinuto);

            //Segunda parte
            for (int min = minuto; min <= 90; min++)
            {
                //Si se ha pulsado el botón de Pausa salimos del bucle
                if (pausa)
                    break;

                //Comenzamos el minuto actual
                bwWorker.ReportProgress(0, new EventoReporte(minuto, null, ""));

                //Buscamos las ocasiones de mi partido en el minuto actual
                List<Ocasion> ocasionesMinuto = reportePropio.buscarOcasiones(minuto);

                foreach (Ocasion oc in ocasionesMinuto)
                {
                    bwWorker.ReportProgress(1, new EventoReporte(minuto, null, "Minuto " + oc.minuto));

                    foreach (string jugada in oc.jugadas)
                    {
                        bwWorker.ReportProgress(1, new EventoReporte(minuto, null, jugada));

                        Thread.Sleep(tiempoJugada);
                    }

                    bwWorker.ReportProgress(1, new EventoReporte(minuto, null, ""));
                }

                //Buscamos las ocasiones del minuto de juego actual para cada partido
                if (actualizarEventos)
                {
                    foreach (ReportePartido rep in reportes)
                    {
                        ocasionesMinuto = rep.buscarOcasiones(min);

                        //Buscamos si hay goles en las ocasiones
                        foreach (Ocasion oc in ocasionesMinuto)
                        {
                            if (oc.existeEnJugadas("¡GOL!"))
                            {
                                //Reportamos el gol
                                EventoReporte ev = new EventoReporte(minuto, rep.partido, oc.jugadas[oc.jugadas.Count - 1]);
                                bwWorker.ReportProgress(0, ev);
                            }
                        }
                    }
                }

                //Incrementamos el minuto actual
                Thread.Sleep(tiempoMinuto);
                minuto++;
            }
        }

        private void bwWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            EventoReporte ev = (EventoReporte)e.UserState;

            if (e.ProgressPercentage == 0)
            {
                lblMinuto.Text = ev.minuto.ToString();

                if (!ev.evento.Equals(""))
                {
                    if (ev.evento.Equals("DESCANSO PARTIDOS"))
                    {
                        lstEventos.Items.Add("DESCANSO PARTIDOS");
                    }
                    else
                    {
                        lstEventos.Items.Add("Min " + ev.minuto + ": " + ev.partido.ToString() + " " + ev.evento);

                        if (actualizarClasificacion)
                        {
                            //Actualizamos la clasificación
                            refrescarClasificacion(ev.partido, ev.evento);
                        }
                    }

                    lstEventos.SelectedIndex = lstEventos.Items.Count - 1;
                    lstEventos.SelectedIndex = - 1;
                }
            }
            else 
            {
                lstReporte.Items.Add(ev.evento);
                lstReporte.SelectedIndex = lstReporte.Items.Count - 1;
                lstReporte.SelectedIndex = - 1;
            }
        }

        private void refrescarClasificacion(Partido partido, string resultado)
        {
            string resultadoAux = resultado.Substring(1, resultado.Length - 2);
            string[] goles = resultadoAux.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);

            int golesLocal = Convert.ToInt32(goles[0]);
            int golesVisitante = Convert.ToInt32(goles[1]);

            Equipo eqLocal = null;
            Equipo eqVisitante = null;

            //Eliminamos los equipos del partido actualizado
            clasificacionProvisional.Remove(new Equipo(Convert.ToInt32(partido.idPropio), ""));
            clasificacionProvisional.Remove(new Equipo(Convert.ToInt32(partido.idOponente), ""));

            //Buscamos los equipos participantes en el partido
            int ind1 = clasificacionInicial.IndexOf(new Equipo(Convert.ToInt32(partido.idPropio), ""));
            int ind2 = clasificacionInicial.IndexOf(new Equipo(Convert.ToInt32(partido.idOponente), ""));

            if (partido.campo.Equals("home"))
            {
                eqLocal = clasificacionInicial[ind1].clonar();
                eqVisitante = clasificacionInicial[ind2].clonar();
            }
            else
            {
                eqLocal = clasificacionInicial[ind2].clonar();
                eqVisitante = clasificacionInicial[ind1].clonar();
            }

            //Actualizamos los datos de los dos equipos implicados
            eqLocal.golesFavor += golesLocal;
            eqLocal.golesContra += golesVisitante;
            eqLocal.ganados += (golesLocal > golesVisitante) ? 1 : 0;
            eqLocal.empatados += (golesLocal == golesVisitante) ? 1 : 0;
            eqLocal.perdidos += (golesLocal < golesVisitante) ? 1 : 0;
            eqLocal.puntos += (golesLocal > golesVisitante) ? 3 : ((golesLocal == golesVisitante) ? 1 : 0);

            eqVisitante.golesFavor += golesVisitante;
            eqVisitante.golesContra += golesLocal;
            eqVisitante.ganados += (golesVisitante > golesLocal) ? 1 : 0;
            eqVisitante.empatados += (golesLocal == golesVisitante) ? 1 : 0;
            eqVisitante.perdidos += (golesVisitante < golesLocal) ? 1 : 0;
            eqVisitante.puntos += (golesLocal > golesVisitante) ? 0 : ((golesLocal == golesVisitante) ? 1 : 3);

            //Insertamos los dos equipos en la clasificación
            clasificacionProvisional.Add(eqLocal);
            clasificacionProvisional.Add(eqVisitante);

            //Ordenamos la clasificación
            clasificacionProvisional.Sort();
            clasificacionProvisional.Reverse();
            
            //Actualizamos la tabla de clasificación
            lstClasificacion.Items.Clear();
            for (int i = 0; i < clasificacionProvisional.Count; i++)
            {
                Equipo eq = clasificacionProvisional[i];

                ListViewItem li = new ListViewItem(new string[4] { (i + 1).ToString(), eq.nombre, eq.puntos.ToString(), (eq.golesFavor - eq.golesContra).ToString() });
                li.Tag = eq;
                lstClasificacion.Items.Add(li);
            }
        }

        private List<Equipo> calcularClasificacionInicial()
        {
            List<Equipo> ci = new List<Equipo>();

            foreach (ReportePartido rep in reportes)
            {
                revertirClasificacion(ci, rep.partido);
            }

            //Ordenamos la clasificación
            ci.Sort();
            ci.Reverse();

            return ci;
        }

        private void revertirClasificacion(List<Equipo> ci, Partido partido)
        {
            string[] goles = partido.resultado.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);

            int golesLocal = Convert.ToInt32(goles[0]);
            int golesVisitante = Convert.ToInt32(goles[1]);

            Equipo eqLocal = null;
            Equipo eqVisitante = null;

            //Buscamos el equipo local en la clasificación inicial
            foreach (Equipo eq in equiposGrupo)
            {
                if (eq.id.ToString().Equals(partido.idPropio))
                {
                    if (partido.campo.Equals("home"))
                        eqLocal = eq.clonar();
                    else
                        eqVisitante = eq.clonar();
                }
            }

            //Buscamos el equipo visitante en la clasificación inicial
            foreach (Equipo eq in equiposGrupo)
            {
                if (eq.id.ToString().Equals(partido.idOponente))
                {
                    if (partido.campo.Equals("home"))
                        eqVisitante = eq.clonar();
                    else
                        eqLocal = eq.clonar();
                }
            }

            //Actualizamos los datos de los dos equipos implicados
            eqLocal.golesFavor -= golesLocal;
            eqLocal.golesContra -= golesVisitante;
            eqLocal.ganados -= (golesLocal > golesVisitante) ? 1 : 0;
            eqLocal.empatados -= (golesLocal == golesVisitante) ? 1 : 0;
            eqLocal.perdidos -= (golesLocal < golesVisitante) ? 1 : 0;
            eqLocal.puntos -= (golesLocal > golesVisitante) ? 3 : ((golesLocal == golesVisitante) ? 1 : 0);

            eqVisitante.golesFavor -= golesVisitante;
            eqVisitante.golesContra -= golesLocal;
            eqVisitante.ganados -= (golesVisitante > golesLocal) ? 1 : 0;
            eqVisitante.empatados -= (golesLocal == golesVisitante) ? 1 : 0;
            eqVisitante.perdidos -= (golesVisitante < golesLocal) ? 1 : 0;
            eqVisitante.puntos -= (golesLocal > golesVisitante) ? 0 : ((golesLocal == golesVisitante) ? 1 : 3);

            //Insertamos los dos equipos en la clasificación
            ci.Add(eqLocal);
            ci.Add(eqVisitante);
        }

        private void bwWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(!pausa)
                lstEventos.Items.Add("FIN PARTIDOS");
        }

        private void lstReporte_DrawItem(object sender, DrawItemEventArgs e)
        {
            Graphics g = e.Graphics;

            SolidBrush br = new SolidBrush(Color.Black);
            string s = "";

            try
            {
                s = lstReporte.Items[e.Index].ToString();
            }
            catch(Exception)
            {
                s = "";
            }

            if ((e.State & DrawItemState.Selected) != 0)
            {
                g.FillRectangle(Brushes.LightBlue, e.Bounds);
                //g.DrawRectangle(Pens.DarkBlue, e.Bounds);
            }
            else
            {
                g.FillRectangle(Brushes.White, e.Bounds);
            }

            Font f = null;
            if (s.StartsWith("Minut") || 
                s.StartsWith("Tiro libre") || 
                s.StartsWith("Saque de esquina") ||
                s.StartsWith("Saque de banda") ||
                s.StartsWith("¡Ocasión de gol!") ||
                s.StartsWith("¡GOL!") ||
                s.StartsWith("DESCANSO"))
                f = new Font(lstReporte.Font, FontStyle.Bold);
            else
                f = lstReporte.Font;

            g.DrawString(s, f, br, e.Bounds);
        }

        private void lstReporte_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            Graphics g = e.Graphics;
            string s = "";

            try
            {
                s = lstReporte.Items[e.Index].ToString();
            }
            catch (Exception)
            {
                s = "";
            }

            SizeF sz = g.MeasureString(s, lstReporte.Font, lstReporte.Width - 5 - SystemInformation.VerticalScrollBarWidth);

            e.ItemHeight = (int)sz.Height + 5;
            e.ItemWidth = (int)sz.Width + 15;
        }

        private void bwWorkerCarga_DoWork(object sender, DoWorkEventArgs e)
        {
            if (partidoPropio == null)
                cargarPartidosDirecto();
            else
                cargaPartido();
        }

        private void bwWorkerCarga_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            pbCargaJornada.PerformStep();
        }

        private void bwWorkerCarga_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Se actualizan los nombres de los equipos en los gráficos de alineación
            lblLocal.Text = partidoPropio.campo.Equals("home") ? partidoPropio.nombrePropio : partidoPropio.nombreOponente;
            lblVisitante.Text = partidoPropio.campo.Equals("home") ? partidoPropio.nombreOponente : partidoPropio.nombrePropio;

            lblLocalFinal.Text = partidoPropio.campo.Equals("home") ? partidoPropio.nombrePropio : partidoPropio.nombreOponente;
            lblVisitanteFinal.Text = partidoPropio.campo.Equals("home") ? partidoPropio.nombreOponente : partidoPropio.nombrePropio;

            //Cargamos las alineaciones

            lstLocalInicio.Items.Clear();
            lstLocalFinal.Items.Clear();
            lstVisitanteInicio.Items.Clear();
            lstVisitanteFinal.Items.Clear();

            //Inicio
            if (reportePropio.titularesLocal.Count == 11 && reportePropio.titularesVisitante.Count == 11)
            {
                for (int i = 0; i < 11; i++)
                {
                    lstLocalInicio.Items.Add(new ListViewItem(new string[] { reportePropio.titularesLocal[i].id.ToString(), reportePropio.titularesLocal[i].posicion, reportePropio.titularesLocal[i].nombre, ""}, lstLocalInicio.Groups[0]));
                    lstVisitanteInicio.Items.Add(new ListViewItem(new string[] { reportePropio.titularesVisitante[i].id.ToString(), reportePropio.titularesVisitante[i].posicion, reportePropio.titularesVisitante[i].nombre, "" }, lstVisitanteInicio.Groups[0]));
                }
            }
            for (int i = 0; i < reportePropio.suplentesLocal.Count; i++)
            {
                lstLocalInicio.Items.Add(new ListViewItem(new string[] { reportePropio.suplentesLocal[i].id.ToString(), "S", reportePropio.suplentesLocal[i].nombre, "" }, lstLocalInicio.Groups[1]));
            }
            for (int i = 0; i < reportePropio.suplentesVisitante.Count; i++)
            {
                lstVisitanteInicio.Items.Add(new ListViewItem(new string[] { reportePropio.suplentesVisitante[i].id.ToString(), "S", reportePropio.suplentesVisitante[i].nombre, "" }, lstVisitanteInicio.Groups[1]));
            }

            //Fin
            if (reportePropio.titularesLocalFin.Count == 11 && reportePropio.titularesVisitanteFin.Count == 11)
            {
                for (int i = 0; i < 11; i++)
                {
                    lstLocalFinal.Items.Add(new ListViewItem(new string[] { reportePropio.titularesLocalFin[i].id.ToString(), reportePropio.titularesLocalFin[i].posicion, reportePropio.titularesLocalFin[i].nombre, "" }, lstLocalFinal.Groups[0]));
                    lstVisitanteFinal.Items.Add(new ListViewItem(new string[] { reportePropio.titularesVisitanteFin[i].id.ToString(), reportePropio.titularesVisitanteFin[i].posicion, reportePropio.titularesVisitanteFin[i].nombre, "" }, lstVisitanteFinal.Groups[0]));
                }
            }
            for (int i = 0; i < reportePropio.suplentesLocalFin.Count; i++)
            {
                lstLocalFinal.Items.Add(new ListViewItem(new string[] { reportePropio.suplentesLocalFin[i].id.ToString(), reportePropio.suplentesLocalFin[i].posicion.Equals("") ? "S" : reportePropio.suplentesLocalFin[i].posicion, reportePropio.suplentesLocalFin[i].nombre, "" }, lstLocalFinal.Groups[1]));
            }
            for (int i = 0; i < reportePropio.suplentesVisitanteFin.Count; i++)
            {
                lstVisitanteFinal.Items.Add(new ListViewItem(new string[] { reportePropio.suplentesVisitanteFin[i].id.ToString(), reportePropio.suplentesVisitanteFin[i].posicion.Equals("") ? "S" : reportePropio.suplentesVisitanteFin[i].posicion, reportePropio.suplentesVisitanteFin[i].nombre, "" }, lstVisitanteFinal.Groups[1]));
            }


            //Cargamos la clasificación provisional
            if (actualizarClasificacion)
            {
                for (int i = 0; i < clasificacionProvisional.Count; i++)
                {
                    Equipo eq = clasificacionProvisional[i];

                    ListViewItem li = new ListViewItem(new string[4] { (i + 1).ToString(), eq.nombre, eq.puntos.ToString(), (eq.golesFavor - eq.golesContra).ToString() });
                    li.Tag = eq;
                    lstClasificacion.Items.Add(li);
                }
            }

            //Se actualizan los gráficos de alineación
            foreach (Jugador j in reportePropio.titularesLocal)
            {
                luInicialLocal.addObject(new FKLineup.CirclePlayer(j, 10, 10, 10, 10));
            }

            foreach (Jugador j in reportePropio.titularesVisitante)
            {
                luInicialVisitante.addObject(new FKLineup.CirclePlayer(j, 10, 10, 10, 10));
            }

            foreach (Jugador j in reportePropio.titularesLocalFin)
            {
                Jugador jAux = j.clonar();
                jAux.posicion = jAux.posicion.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0].Trim();

                luLocalFinal.addObject(new FKLineup.CirclePlayer(jAux, 10, 10, 10, 10));
            }

            foreach (Jugador j in reportePropio.titularesVisitanteFin)
            {
                Jugador jAux = j.clonar();
                jAux.posicion = jAux.posicion.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0].Trim();

                luVisitanteFinal.addObject(new FKLineup.CirclePlayer(jAux, 10, 10, 10, 10));
            }

            luInicialLocal.reorganizePlayers();
            luInicialVisitante.reorganizePlayers();
            luLocalFinal.reorganizePlayers();
            luVisitanteFinal.reorganizePlayers();

            lblEstado.Text = "Carga finalizada.";

            btnReproducir.Enabled = true;
        }

        private void generarHtml(ReportePartido rpt)
        {
            //Lista de Jugadas del Partido

            StringBuilder listaJugadas = new StringBuilder();

            bool sombreado = false;
            foreach (Ocasion oca in rpt.ocasiones)
            {
                if (sombreado)
                    listaJugadas.Append("<ul style=\"background-color: #f0f0f0; list-style:none; margin: 0; padding:2px 5px 10px 0px;\">");
                else
                    listaJugadas.Append("<ul style=\"background-color: #fff; list-style:none; margin: 0; padding:2px 5px 10px 0px;\">");

                if(oca.minuto == -45)
                    listaJugadas.Append("<li style=\"font-weight:bold;\">DESCANSO</li>");
                else
                    listaJugadas.Append("<li style=\"font-weight:bold;\">Minuto " + oca.minuto + "</li>");

                foreach (string acc in oca.jugadas)
                {
                    if (acc.Equals("Saque de banda")    ||
                        acc.Equals("Saque de esquina")  ||
                        acc.Equals("¡Ocasión de gol!")  ||
                        acc.Equals("Tiro libre") )
                    {
                        listaJugadas.Append("<li>&nbsp;</li>");
                    }

                    if(acc.Equals("¡Ocasión de gol!"))
                        listaJugadas.Append("<li style=\"font-weight:bold;\">¡Ocasión de gol!</li>");
                    else
                        listaJugadas.Append("<li>" + acc + "</li>");
                }

                listaJugadas.Append("</ul>");

                sombreado = !sombreado;
            }

            //Leemos las plantillas del reporte y las alineaciones
            //string plantillaAlineacion = "";
            string plantillaReporte = "";

            try
            {
                StreamReader sr = null;

                //sr = new StreamReader("temp\\plantilla-alineacion.html", Encoding.UTF8);
                //plantillaAlineacion = sr.ReadToEnd();
                //sr.Close();

                sr = new StreamReader("temp\\plantilla-reporte.html", Encoding.UTF8);
                plantillaReporte = sr.ReadToEnd();
                sr.Close();
            }
            catch (Exception)
            {
                MessageBox.Show("Error de lectura en plantillas.", "Error");
            }

            //Sustituimos los parámetros
            //string htmlAlineacionInicio = "";
            //string htmlAlineacionFinal = "";
            string htmlReporte = "";

            //htmlAlineacionInicio = plantillaAlineacion.Replace("$$$equipo-local$$$", partidoPropio.campo.Equals("home") ? partidoPropio.nombrePropio : partidoPropio.nombreOponente);
            //htmlAlineacionInicio = htmlAlineacionInicio.Replace("$$$equipo-visitante$$$", partidoPropio.campo.Equals("home") ? partidoPropio.nombreOponente : partidoPropio.nombrePropio);
            //htmlAlineacionInicio = htmlAlineacionInicio.Replace("$$$titulares$$$", htmlTitularesInicio.ToString());
            //htmlAlineacionInicio = htmlAlineacionInicio.Replace("$$$suplentes$$$", htmlSuplentesInicio.ToString());

            htmlReporte = plantillaReporte.Replace("$$$jugadas-partido$$$", listaJugadas.ToString());

            //htmlAlineacionFinal = plantillaAlineacion.Replace("$$$equipo-local$$$", partidoPropio.campo.Equals("home") ? partidoPropio.nombrePropio : partidoPropio.nombreOponente);
            //htmlAlineacionFinal = htmlAlineacionFinal.Replace("$$$equipo-visitante$$$", partidoPropio.campo.Equals("home") ? partidoPropio.nombreOponente : partidoPropio.nombrePropio);
            //htmlAlineacionFinal = htmlAlineacionFinal.Replace("$$$titulares$$$", htmlTitularesFin.ToString());
            //htmlAlineacionFinal = htmlAlineacionFinal.Replace("$$$suplentes$$$", htmlSuplentesFin.ToString());

            try
            {
                StreamWriter sw = null;

                //sw = new StreamWriter("temp\\alineacion-inicial.html", false, Encoding.UTF8);
                //sw.Write(htmlAlineacionInicio);
                //sw.Close();

                //sw = new StreamWriter("temp\\alineacion-final.html", false, Encoding.UTF8);
                //sw.Write(htmlAlineacionFinal);
                //sw.Close();

                sw = new StreamWriter("temp\\reporte.html", false, Encoding.UTF8);
                sw.Write(htmlReporte);
                sw.Close();
            }
            catch (Exception)
            {
                MessageBox.Show("Error de escritura en reporte del partido.", "Error");
            }
        }

        private void FrmVisorPartidos_Load(object sender, EventArgs e)
        {
            tabControl1.SelectedTab = tabPage1;
            tabControl1.SelectedTab = tabPage3;
            tabControl1.SelectedTab = tabPage4;
            tabControl1.SelectedTab = tabPage2;

            //if (partidoPropio != null)
            //    tabControl1.TabPages.Remove(tabPage1);

            //Carga de la jornada
            bwWorkerCarga.RunWorkerAsync();
        }

        private List<Equipo> clonarClasificacion(List<Equipo> lst)
        {
            List<Equipo> res = new List<Equipo>();

            foreach (Equipo eq in lst)
            {
                res.Add(eq.clonar()); 
            }

            return res;
        }
    }
}
